<?php
/**
 * NC服务器管理服务
 * User: Administrator
 * Date: 2025-10-17
 * Time: 16:00
 */

namespace plugin\csauto\app\service;

use plugin\csauto\app\model\NcServerModel;

class NcServerService
{
    /**
     * 检查NC服务器限速状态
     */
    public static function checkNcServerThrottling()
    {
        addlog('NC_SERVER_CHECK', '开始检查NC服务器限速状态');

        try {
            // 获取所有启用的NC服务器账户
            $ncServers = NcServerModel::query()
                ->where('status', 1)
                ->get();

            if ($ncServers->isEmpty()) {
                addlog('NC_SERVER_CHECK', '未找到启用的NC服务器账户');
                return;
            }

            // 获取所有下载器
            $downloaders = \plugin\csauto\app\model\DownloaderModel::query()
                ->get();

            if ($downloaders->isEmpty()) {
                addlog('NC_SERVER_CHECK', '未找到下载器配置');
                return;
            }

            // 获取限速时的最大任务数配置
            $throttledLimit = SystemService::getConfig(
                SystemService::NC_THROTTLED_TASK_LIMIT
            ) ?: 2;

            // 收集所有VPS服务器的状态信息
            $allThrottledVpsIps = [];  // 被限速的VPS IP列表
            $allNormalVpsIps = [];     // 正常的VPS IP列表

            // 检查每个NC账户下的所有VPS服务器
            foreach ($ncServers as $server) {
                $result = self::checkSingleNcServer($server);
                $vpsList = $result['list'] ?? [];

                // 分类收集VPS的IP地址
                foreach ($vpsList as $vpsInfo) {
                    if ($vpsInfo['throttled']) {
                        $allThrottledVpsIps[] = $vpsInfo['ip'];
                    } else {
                        $allNormalVpsIps[] = $vpsInfo['ip'];
                    }
                }
            }

            // 去重
            $allThrottledVpsIps = array_unique($allThrottledVpsIps);
            $allNormalVpsIps = array_unique($allNormalVpsIps);

            // 根据VPS状态，更新对应下载器的限速标记
            self::updateDownloadersThrottlingStatus(
                $downloaders, 
                $allThrottledVpsIps, 
                $allNormalVpsIps, 
                $throttledLimit
            );

            // 输出汇总信息
            $throttledCount = count($allThrottledVpsIps);
            $normalCount = count($allNormalVpsIps);
            addlog('NC_SERVER_CHECK', "检查完成 - 限速VPS: {$throttledCount}个, 正常VPS: {$normalCount}个");

        } catch (\Exception $e) {
            addlog('NC_SERVER_CHECK', "检查NC服务器限速状态时发生错误: " . $e->getMessage(), 'error');
        }
    }

    /**
     * 检查单个NC账户下所有VPS服务器的限速状态
     * @param NcServerModel $server NC账户信息
     * @param bool $includeTraffic 是否包含流量信息
     * @param bool $includeRawInfo 是否包含原始信息
     * @return array 返回所有VPS列表及统计信息
     */
    public static function checkSingleNcServer($server, $includeTraffic = true, $includeRawInfo = false)
    {
        try {
            // 获取真实的密码（绕过访问器的隐藏处理）
            $realPassword = $server->getRealScpPassword();
            
            // 验证凭据
            if (empty($server->customer_number) || empty($realPassword)) {
                addlog('NC_SERVER_CHECK', "账户 {$server->server_name}: 凭据未配置", 'error');
                return [
                    'list' => [],
                    'throttledCount' => 0,
                    'totalVpsCount' => 0
                ];
            }

            // 创建SOAP客户端
            $wsdlUrl = 'https://www.servercontrolpanel.de/WSEndUser?wsdl';
            $soapClient = new \SoapClient($wsdlUrl, [
                'trace' => 1,
                'exceptions' => true,
                'connection_timeout' => 30,
                'cache_wsdl' => WSDL_CACHE_NONE
            ]);

            // 获取该账户下的所有VPS服务器列表
            $vservers = $soapClient->getVServers([
                'loginName' => $server->customer_number,
                'password' => $realPassword
            ]);

            if (empty($vservers)) {
                addlog('NC_SERVER_CHECK', "账户 {$server->server_name}: 未能获取到VPS信息", 'error');
                return [
                    'list' => [],
                    'throttledCount' => 0,
                    'totalVpsCount' => 0
                ];
            }

            // 添加详细调试：输出原始返回数据
            // addlog('NC_SERVER_CHECK', "  [调试] getVServers返回数据类型: " . gettype($vservers));
            if (is_object($vservers)) {
                $objVars = get_object_vars($vservers);
                // addlog('NC_SERVER_CHECK', "  [调试] 对象属性列表: " . implode(', ', array_keys($objVars)));
                if (!empty($objVars)) {
                    $firstProp = reset($objVars);
                    // addlog('NC_SERVER_CHECK', "  [调试] 第一个属性的类型: " . gettype($firstProp) . (is_array($firstProp) || is_object($firstProp) ? ' (count: ' . count((array)$firstProp) . ')' : ''));
                }
            } elseif (is_array($vservers)) {
                // addlog('NC_SERVER_CHECK', "  [调试] 数组元素数量: " . count($vservers));
            }
            
            // SOAP API 可能返回 stdClass 对象或数组，需要统一处理
            if (is_object($vservers)) {
                // 检查对象是否包含return或item等包装属性
                if (isset($vservers->return)) {
                    $vservers = is_array($vservers->return) ? $vservers->return : [$vservers->return];
                } elseif (isset($vservers->item)) {
                    $vservers = is_array($vservers->item) ? $vservers->item : [$vservers->item];
                } else {
                    // 检查对象的属性，可能VPS列表在某个属性中
                    $objVars = get_object_vars($vservers);
                    if (count($objVars) == 1) {
                        // 如果对象只有一个属性，可能VPS列表就在这个属性中
                        $firstProp = reset($objVars);
                        if (is_array($firstProp) || is_object($firstProp)) {
                            $vservers = is_array($firstProp) ? $firstProp : [$firstProp];
                        } else {
                            // 单个VPS，包装为数组
                            $vservers = [$vservers];
                        }
                    } else {
                        // 多个属性或结构复杂，当作单个VPS处理
                        $vservers = [$vservers];
                    }
                }
            } elseif (!is_array($vservers)) {
                addlog('NC_SERVER_CHECK', "账户 {$server->server_name}: VPS数据格式异常", 'error');
                return [
                    'list' => [],
                    'throttledCount' => 0,
                    'totalVpsCount' => 0
                ];
            }

            $totalVpsCount = count($vservers);
            addlog('NC_SERVER_CHECK', "账户 {$server->server_name} 共有 {$totalVpsCount} 个VPS服务器，开始逐个检查...");
            
            // 添加调试信息：记录返回的数据结构
            if ($totalVpsCount > 0) {
                $firstItem = reset($vservers);
                addlog('NC_SERVER_CHECK', "  [调试] VPS列表第一项数据类型: " . gettype($firstItem));
            }

            $allServers = [];      // 所有VPS列表
            $throttledCount = 0;   // 限速VPS数量

            // 遍历该账户下的每个VPS服务器，检查限速状态
            foreach ($vservers as $vservername) {
                // SOAP API 返回的 VPS 名称可能是对象、数组或字符串
                $vserverNameStr = '';
                
                if (is_object($vservername)) {
                    // 尝试获取对象的属性值，通常是第一个属性或 name 属性
                    if (isset($vservername->name)) {
                        $vserverNameStr = $vservername->name;
                    } else {
                        $vserverArray = (array)$vservername;
                        if (!empty($vserverArray)) {
                            $firstValue = reset($vserverArray);
                            // 如果第一个值还是数组或对象，需要进一步处理
                            if (is_array($firstValue)) {
                                $vserverNameStr = isset($firstValue[0]) ? (string)$firstValue[0] : '';
                            } elseif (is_object($firstValue)) {
                                $vserverNameStr = isset($firstValue->name) ? (string)$firstValue->name : (string)current((array)$firstValue);
                            } else {
                                $vserverNameStr = (string)$firstValue;
                            }
                        }
                    }
                } elseif (is_array($vservername)) {
                    // 如果是数组，尝试获取第一个元素或name键
                    if (isset($vservername['name'])) {
                        $vserverNameStr = (string)$vservername['name'];
                    } elseif (isset($vservername[0])) {
                        $vserverNameStr = (string)$vservername[0];
                    } else {
                        $vserverNameStr = !empty($vservername) ? (string)reset($vservername) : '';
                    }
                } else {
                    // 标量值，直接转换为字符串
                    $vserverNameStr = (string)$vservername;
                }
                
                if (empty($vserverNameStr)) {
                    addlog('NC_SERVER_CHECK', "跳过无效的VPS名称 (原始类型: " . gettype($vservername) . ")", 'warning');
                    continue;
                }
                
                $info = $soapClient->getVServerInformation([
                    'loginName' => $server->customer_number,
                    'password' => $realPassword,
                    'vservername' => $vserverNameStr,
                    'language' => 'en'
                ]);

                // 获取实际的返回数据（SOAP API 会将数据包装在 return 字段中）
                $vpsData = isset($info->return) ? $info->return : $info;

                // 获取IP地址（取第一个IPv4地址）
                $ipAddress = 'N/A';
                if (!empty($vpsData->ips)) {
                    // 处理ips字段，可能是字符串、数组或对象
                    if (is_string($vpsData->ips)) {
                        // 如果是单个字符串，直接使用
                        if (strpos($vpsData->ips, ':') === false) {
                            $ipAddress = $vpsData->ips;
                        }
                    } else {
                        // 转换为数组处理
                        $ips = is_array($vpsData->ips) ? $vpsData->ips : (array)$vpsData->ips;
                        foreach ($ips as $ip) {
                            // 确保是字符串且过滤出IPv4地址（不包含冒号的是IPv4）
                            if (is_string($ip) && strpos($ip, ':') === false && !empty($ip)) {
                                $ipAddress = $ip;
                                break;
                            } elseif (is_object($ip) && isset($ip->ip)) {
                                // 如果IP是对象，尝试获取ip属性
                                if (is_string($ip->ip) && strpos($ip->ip, ':') === false) {
                                    $ipAddress = $ip->ip;
                                    break;
                                }
                            }
                        }
                    }
                }

                // 基础信息
                $serverInfo = [
                    'name' => $vserverNameStr,
                    'ip' => $ipAddress,
                    'account' => $server->server_name
                ];

                // 获取当月流量信息（单位：GB）
                if ($includeTraffic) {
                    $trafficIn = 0;
                    $trafficOut = 0;
                    $trafficTotal = 0;
                    if (!empty($vpsData->currentMonth)) {
                        $trafficIn = $vpsData->currentMonth->in ?? 0;
                        $trafficOut = $vpsData->currentMonth->out ?? 0;
                        $trafficTotal = $vpsData->currentMonth->total ?? 0;
                    }
                    $serverInfo['traffic_in'] = $trafficIn;
                    $serverInfo['traffic_out'] = $trafficOut;
                    $serverInfo['traffic_total'] = $trafficTotal;
                }

                // 检查该VPS的网络接口是否被限速
                $isThrottled = false;
                if (!empty($vpsData->serverInterfaces)) {
                    $interfaces = $vpsData->serverInterfaces;
                    // 如果是单个对象，转换为数组
                    if (is_object($interfaces) && !is_iterable($interfaces)) {
                        $interfaces = [$interfaces];
                    }
                    
                    foreach ($interfaces as $interface) {
                        if (!empty($interface->trafficThrottled)) {
                            $isThrottled = true;
                            break;
                        }
                    }
                }
                $serverInfo['throttled'] = $isThrottled;

                // 添加原始信息（如果需要）
                if ($includeRawInfo) {
                    $serverInfo['raw_info'] = $info;
                }

                $allServers[] = $serverInfo;

                // 输出单个VPS的状态
                if ($isThrottled) {
                    $throttledCount++;
                    addlog('NC_SERVER_CHECK', "  └─ VPS [{$vserverNameStr}] IP: {$ipAddress} - 已被限速 ⚠️");
                } else {
                    addlog('NC_SERVER_CHECK', "  └─ VPS [{$vserverNameStr}] IP: {$ipAddress} - 正常");
                }
            }

            // 汇总日志
            if ($throttledCount > 0) {
                $throttledList = implode(', ', array_column(array_filter($allServers, function($v) {
                    return $v['throttled'];
                }), 'name'));
                addlog('NC_SERVER_CHECK', "账户 {$server->server_name}: {$totalVpsCount}个VPS中有{$throttledCount}个被限速 [{$throttledList}]", 'warning');
            } else {
                addlog('NC_SERVER_CHECK', "账户 {$server->server_name}: 所有 {$totalVpsCount} 个VPS均未被限速");
            }

            // 准备返回数据
            $result = [
                'list' => $allServers,
                'throttledCount' => $throttledCount,
                'totalVpsCount' => $totalVpsCount,
                'vservers' => $vservers
            ];

            // 如果包含流量信息，计算总流量并更新下载器的流量数据
            if ($includeTraffic) {
                $totalTrafficIn = array_sum(array_column($allServers, 'traffic_in'));
                $totalTrafficOut = array_sum(array_column($allServers, 'traffic_out'));
                $totalTraffic = array_sum(array_column($allServers, 'traffic_total'));
                
                $result['totalTrafficIn'] = $totalTrafficIn;
                $result['totalTrafficOut'] = $totalTrafficOut;
                $result['totalTraffic'] = $totalTraffic;

                // 根据 IP 匹配，更新对应下载器的流量信息
                self::updateDownloaderTraffic($allServers);
            }

            return $result;

        } catch (\SoapFault $e) {
            addlog('NC_SERVER_CHECK', "账户 {$server->server_name}: SOAP调用失败 - " . $e->getMessage(), 'error');
            return [
                'list' => [],
                'throttledCount' => 0,
                'totalVpsCount' => 0
            ];
        } catch (\Exception $e) {
            addlog('NC_SERVER_CHECK', "账户 {$server->server_name}: 检查时出错 - " . $e->getMessage(), 'error');
            return [
                'list' => [],
                'throttledCount' => 0,
                'totalVpsCount' => 0
            ];
        }
    }

    /**
     * 根据VPS状态更新下载器的限速标记
     * @param $downloaders 所有下载器列表
     * @param array $throttledIps 被限速的VPS IP地址列表
     * @param array $normalIps 正常的VPS IP地址列表
     * @param int $throttledLimit 限速时的任务数限制
     */
    private static function updateDownloadersThrottlingStatus($downloaders, $throttledIps, $normalIps, $throttledLimit)
    {
        // 输出状态信息
        if (!empty($throttledIps)) {
            addlog('NC_SERVER_CHECK', '被限速的VPS IP列表: ' . implode(', ', $throttledIps));
        }
        if (!empty($normalIps)) {
            addlog('NC_SERVER_CHECK', '正常的VPS IP列表: ' . implode(', ', $normalIps));
        }

        $markedCount = 0;      // 标记为限速的数量
        $unmarkedCount = 0;    // 解除限速的数量
        $unchangedCount = 0;   // 状态未变的数量

        foreach ($downloaders as $downloader) {
            // 获取下载器的host地址（字段名是 d_host）
            $downloaderHost = $downloader->d_host ?? '';
            
            // 解析下载器host，提取IP地址（可能是 http://1.2.3.4:8080 这样的格式）
            $downloaderIp = self::extractIpFromHost($downloaderHost);
            
            if (empty($downloaderIp)) {
                addlog('NC_SERVER_CHECK', "下载器 [{$downloader->d_name}] 无法提取IP地址 (d_host: {$downloaderHost})");
                continue;
            }
            
            // 判断该下载器的IP是否在限速列表中
            $isInThrottledList = in_array($downloaderIp, $throttledIps);
            $isInNormalList = in_array($downloaderIp, $normalIps);
            
            if ($isInThrottledList) {
                // VPS被限速，下载器需要标记为限速
                if ($downloader->nc_throttled != 1) {
                    $downloader->nc_throttled = 1;
                    $downloader->save();

                    $actualLimit = self::getEffectiveTaskLimit($downloader, $throttledLimit);
                    addlog('NC_SERVER_CHECK', "✓ 标记下载器 [{$downloader->d_name}] ({$downloaderIp}) 为限速状态，任务限制: {$actualLimit}", 'warning');
                    $markedCount++;
                } else {
                    addlog('NC_SERVER_CHECK', "- 下载器 [{$downloader->d_name}] ({$downloaderIp}) 保持限速状态");
                    $unchangedCount++;
                }
            } elseif ($isInNormalList) {
                // VPS正常，下载器需要解除限速标记
                if ($downloader->nc_throttled == 1) {
                    $downloader->nc_throttled = 0;
                    $downloader->save();
                    
                    addlog('NC_SERVER_CHECK', "✓ 解除下载器 [{$downloader->d_name}] ({$downloaderIp}) 的限速标记，恢复任务限制: {$downloader->task_limit}");
                    $unmarkedCount++;
                } else {
                    addlog('NC_SERVER_CHECK', "- 下载器 [{$downloader->d_name}] ({$downloaderIp}) 保持正常状态");
                    $unchangedCount++;
                }
            } else {
                // IP不在任何VPS列表中（可能是其他服务器）
                addlog('NC_SERVER_CHECK', "! 下载器 [{$downloader->d_name}] ({$downloaderIp}) 不在NC VPS列表中，保持当前状态");
            }
        }

        // 输出汇总统计
        addlog('NC_SERVER_CHECK', "下载器状态更新完成 - 新增限速: {$markedCount}, 解除限速: {$unmarkedCount}, 未变化: {$unchangedCount}");
    }

    /**
     * 从下载器d_host地址中提取IP地址
     * @param string $host 下载器d_host地址（如：http://1.2.3.4:8080 或 1.2.3.4:8080 或 1.2.3.4）
     * @return string 提取的IP地址
     */
    private static function extractIpFromHost($host)
    {
        if (empty($host)) {
            return '';
        }
        
        // 去除协议部分（http:// 或 https://）
        $host = preg_replace('#^https?://#', '', $host);
        
        // 去除端口部分（:8080）
        $host = preg_replace('#:\d+.*$#', '', $host);
        
        // 去除路径部分
        $host = explode('/', $host)[0];
        
        return trim($host);
    }

    /**
     * 获取下载器的实际任务限制（考虑限速状态）
     * @param $downloader
     * @param $throttledLimit
     * @return int
     */
    private static function getEffectiveTaskLimit($downloader, $throttledLimit = null)
    {
        // 如果下载器被限速，使用限速限制
        if ($downloader->nc_throttled == 1) {
            if ($throttledLimit === null) {
                $throttledLimit = SystemService::getConfig(
                    SystemService::NC_THROTTLED_TASK_LIMIT
                ) ?: 2;
            }
            return min($downloader->task_limit, $throttledLimit);
        }

        // 否则返回原始的任务限制
        return $downloader->task_limit;
    }

    /**
     * 根据VPS流量信息更新对应下载器的流量数据
     * @param array $vpsServers VPS服务器列表，每个元素包含 ip, traffic_in, traffic_out, traffic_total 等字段
     */
    private static function updateDownloaderTraffic($vpsServers)
    {
        if (empty($vpsServers)) {
            return;
        }

        // 获取所有下载器
        $downloaders = \plugin\csauto\app\model\DownloaderModel::query()->get();

        if ($downloaders->isEmpty()) {
            addlog('NC_SERVER_CHECK', '未找到下载器配置，无法更新流量信息');
            return;
        }

        $updatedCount = 0;
        $notFoundCount = 0;

        // 遍历每个 VPS，根据 IP 匹配下载器并更新流量
        foreach ($vpsServers as $vps) {
            $vpsIp = $vps['ip'] ?? '';
            if (empty($vpsIp) || $vpsIp === 'N/A') {
                continue;
            }

            // 查找匹配的下载器
            $matchedDownloader = null;
            foreach ($downloaders as $downloader) {
                $downloaderHost = $downloader->d_host ?? '';
                $downloaderIp = self::extractIpFromHost($downloaderHost);
                
                if ($downloaderIp === $vpsIp) {
                    $matchedDownloader = $downloader;
                    break;
                }
            }

            // 如果找到匹配的下载器，更新流量信息
            if ($matchedDownloader) {
                $matchedDownloader->traffic_in = $vps['traffic_in'] ?? 0;
                $matchedDownloader->traffic_out = $vps['traffic_out'] ?? 0;
                $matchedDownloader->traffic_total = $vps['traffic_total'] ?? 0;
                $matchedDownloader->last_traffic_check_at = date('Y-m-d H:i:s');
                $matchedDownloader->save();

                addlog('NC_SERVER_CHECK', "✓ 更新下载器 [{$matchedDownloader->d_name}] ({$vpsIp}) 流量: 入站{$vps['traffic_in']}GB, 出站{$vps['traffic_out']}GB, 总计{$vps['traffic_total']}GB");
                $updatedCount++;
            } else {
                addlog('NC_SERVER_CHECK', "! VPS IP {$vpsIp} 未找到匹配的下载器");
                $notFoundCount++;
            }
        }

        // 输出汇总统计
        if ($updatedCount > 0 || $notFoundCount > 0) {
            addlog('NC_SERVER_CHECK', "流量更新完成 - 成功更新: {$updatedCount}个, 未匹配: {$notFoundCount}个");
        }
    }
}

